import responseUtils from '@/core/utils/responseUtils'
import lodash from 'lodash'
import promiseUtils from '@/core/utils/promiseUtils'
import { R } from '@/components/axios/interface'
import oauth2ServerApi from '@/core/oauth2/serverapi/oauth2ServerApi'
import useAccountTokenInfoStore from '@/core/account/store/useAccountTokenInfoStore'
import Oauth2IntrospectResponse from '@/core/oauth2/types/model/response/Oauth2IntrospectResponse'
import Oauth2UserInfoDto from '@/core/oauth2/types/model/dto/Oauth2UserInfoDto'
import LoginByPasswordRequest from '@/core/oauth2/types/model/request/LoginByPasswordRequest'
import Oauth2TokenInfoDto from '@/core/oauth2/types/model/dto/Oauth2TokenInfoDto'
import { TokenInfoResponse } from '@/core/oauth2/types/model/response/TokenInfoResponse'

class Oauth2Manager {
	logout = (): Promise<R> => {
		const token = useAccountTokenInfoStore.getState()?.accessToken
		if (lodash.isNil(token)) {
			return promiseUtils.okWithNil()
		}
		return promiseUtils.ofResponse(oauth2ServerApi.logout(token)).origin()
	}

	introspectByClient = async (accessToken: string, clientId: string, clientSecret: string): Promise<Oauth2IntrospectResponse> => {
		return await promiseUtils.ofResponse(oauth2ServerApi.introspectByClient(accessToken, clientId, clientSecret)).check()
	}

	validTokenActive = async (accessToken: string, clientId: string, clientSecret: string): Promise<boolean> => {
		const introspectR = await promiseUtils
			.ofResponse(oauth2ServerApi.introspectByClient(accessToken, clientId, clientSecret))
			.check()
		return introspectR.active
	}
	convertOauth2UserInfoFromOauth2IntrospectResponse = (res: Oauth2IntrospectResponse): Oauth2UserInfoDto => {
		return {
			id: res.userinfo?.id,
			attributes: res.userinfo?.attributes,
			authorities: res.userinfo?.authorities,
		}
	}
	getTokenByPasswordGrantType = async (data: LoginByPasswordRequest): Promise<Oauth2TokenInfoDto> => {
		return promiseUtils
			.ofResponse(oauth2ServerApi.loginByPassword(data))
			.ifSuccessConvert(async res => {
				return this.toOauth2TokenInfoDtoRFromTokenInfoResponseR(res)
			})
			.check()
	}

	getTokenByClientGrantType = async (clientId: string, clientSecret: string): Promise<Oauth2TokenInfoDto> => {
		return promiseUtils
			.ofResponse(oauth2ServerApi.getTokenByClientGrantType(clientId, clientSecret))
			.ifSuccessConvert(async res => {
				return this.toOauth2TokenInfoDtoRFromTokenInfoResponseR(res)
			})
			.check()
	}

	toOauth2TokenInfoDtoRFromTokenInfoResponseR = (res: R<TokenInfoResponse>): R<Oauth2TokenInfoDto> => {
		if (responseUtils.isFailure(res)) {
			return <R<Oauth2TokenInfoDto>>(<any>res)
		}
		const tokenInfo: Oauth2TokenInfoDto = {
			accessToken: res.data?.access_token,
			refreshToken: res.data?.refresh_token,
			tokenType: res.data?.token_type,
			expiresIn: res.data?.expires_in,
			scope: res.data?.scope,
		}
		return {
			code: res.code,
			message: res.message,
			data: tokenInfo,
		} as R<Oauth2TokenInfoDto>
	}
}

export default new Oauth2Manager()
